#include <list.h>
#include <sync.h>
#include <proc.h>
#include <sched.h>
#include <assert.h>

void
wakeup_proc(struct proc_struct *proc) {
    assert(proc->state != PROC_ZOMBIE);
    bool intr_flag;
    local_intr_save(intr_flag);
    {
        if (proc->state != PROC_RUNNABLE) {
            proc->state = PROC_RUNNABLE;
            proc->wait_state = 0;
        }
        else {
            warn("wakeup runnable process.\n");
        }
    }
    local_intr_restore(intr_flag);
}

void
schedule(void) {
    bool intr_flag;                      // 保存当前中断状态
    list_entry_t *le, *last;             // le为当前遍历的链表节点, last为起始遍历节点
    struct proc_struct *next = NULL;     // 指向下一个将被调度的进程

    // 禁用中断，保存当前中断状态
    local_intr_save(intr_flag);

    {
        current->need_resched = 0;       // 重置当前进程的调度标志，表示当前已响应调度请求

        // 确定从哪里开始遍历进程链表
        last = (current == idleproc) ? &proc_list : &(current->list_link);
        le = last;

        // 遍历链表，寻找状态为 PROC_RUNNABLE 的进程
        do {
            // 移动到下一个节点
            if ((le = list_next(le)) != &proc_list) {
                // 将链表节点转换为进程结构体
                next = le2proc(le, list_link);

                // 如果找到一个可运行的进程，退出循环
                if (next->state == PROC_RUNNABLE) {
                    break;
                }
            }
        } while (le != last);           // 如果遍历了一圈回到起始节点，则退出循环

        // 如果没有找到可运行的进程，或者找到的进程不可运行，则选择空闲进程
        if (next == NULL || next->state != PROC_RUNNABLE) {
            next = idleproc;            // 保证系统至少有一个进程在运行
        }

        // 增加选中进程的运行次数统计
        next->runs++;

        // 如果选中的进程与当前运行的进程不同，则进行上下文切换
        if (next != current) {
            proc_run(next);             // 切换到选中的进程运行
        }
    }

    // 恢复中断状态
    local_intr_restore(intr_flag);
}

